package com.linsen.uaa.controller;

import cn.dev33.satoken.session.SaSession;
import cn.dev33.satoken.stp.StpUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.linsen.core.common.constant.AuthConstant;
import com.linsen.core.common.constant.LinsenConstant;
import com.linsen.core.common.context.TokenContextHolder;
import com.linsen.core.common.enums.LoginEndpointType;
import com.linsen.core.common.exception.RequestBusinessException;
import com.linsen.core.common.model.User;
import com.linsen.core.common.util.*;
import com.linsen.core.log.enums.LogType;
import com.linsen.core.log.enums.LoginType;
import com.linsen.core.log.event.LogEvent;
import com.linsen.core.ohc.util.OHCacheUtil;
import com.linsen.core.redis.util.RedisSecurityUtil;
import com.linsen.core.satoken.constant.SaTokenConstant;
import com.linsen.erp.admin.provider.feign.IAdminFeignClient;
import com.linsen.erp.admin.provider.vo.SystemUserVO;
import com.linsen.uaa.provider.dto.ImgCaptchaDTO;
import com.linsen.uaa.provider.dto.LoginDTO;
import com.linsen.uaa.provider.enums.LoginAccountType;
import com.linsen.uaa.provider.vo.ImgCaptchaVO;
import com.linsen.uaa.provider.vo.LoginVO;
import com.linsen.uaa.service.IValidateService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiOperation;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.ApplicationContext;
import org.springframework.http.HttpHeaders;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import springfox.documentation.annotations.ApiIgnore;

import javax.servlet.http.HttpServletRequest;
import java.time.LocalDateTime;
import java.util.List;

/**
 * @author zhaoyong
 * @date 2023/3/10
 */
@Slf4j
@RestController
@RequestMapping("/auth")
@RequiredArgsConstructor
@Api(value = "登录管理", tags = "登录认证鉴权")
public class AuthController {
    private final IValidateService validateService;
    private final RedisSecurityUtil redisSecurityUtil;
    private final OHCacheUtil<Object> ohCacheUtil;
    private final IAdminFeignClient iAdminFeignClient;
    private final ApplicationContext applicationContext;

    @ApiOperation(value = "获取图形验证码", response = ImgCaptchaVO.class)
    @GetMapping("/captcha/img")
    public Result getImgCaptcha() {
        return Result.data(ConvertUtil.convert(this.validateService.getImgCaptcha(), ImgCaptchaVO.class));
    }

    @ApiOperation(value = "发送手机验证码")
    @PostMapping("/captcha/sms")
    @ApiImplicitParam(name = "mobile", value = "手机号", required = true, dataType = "string")
    public Result sendSmsCaptcha(@ApiIgnore @RequestParam String mobile) {
        this.validateService.sendSmsCaptcha(mobile);
        return Result.ok();
    }

    @ApiOperation(value = "PC登录", response = LoginVO.class)
    @PostMapping("/login")
    public Result login(@RequestBody @Validated LoginDTO dto, HttpServletRequest request) {
        LoginEndpointType loginEndpointType = dto.getLoginEndpointType();
        String username = dto.getUsername();
        String password = ShaUtil.encrypt(RSAUtil.decrypt(dto.getPassword()));//前端sha256加密后提交
        LoginAccountType loginAccountType = dto.getLoginAccountType();
        ImgCaptchaDTO captcha = dto.getCaptcha();

        //优先验证图形验证码
        switch (loginEndpointType) {
            case SYSTEM:
                this.validateService.checkImgCaptcha(captcha.getKey(), captcha.getCode());
                break;
            case APP:
                break;
            default:
                return Result.error("登录客户端类型错误");
        }

        String userid = null;
        String name = null;
        String deptId = null;
        List<String> roleList = null;
        List<String> permissionList = null;
        Integer isSuper = null;
        Integer isAdmin = null;
        Integer permissionType = null;//数据权限是否包含全部：0，否；1，是
        List<String> roleDataScopeDeptIdList = null;//数据权限自定义范围id列表-部门
        List<String> roleDataScopeUserIdList = null;//数据权限自定义范围id列表-用户
        if (ObjectUtil.equal(loginAccountType, LoginAccountType.PASSWORD)) {
            switch (loginEndpointType) {
                case SYSTEM:
                    Result result1 = iAdminFeignClient.loginCheckByUsername(username, password);
                    if (result1.hasError()) {
                        return result1;
                    }
                    SystemUserVO systemUserVO = result1.getData(SystemUserVO.class);
                    userid = systemUserVO.getUserid();
                    username = systemUserVO.getUsername();
                    name = systemUserVO.getName();
                    deptId = systemUserVO.getDeptId();
                    roleList = systemUserVO.getRoleList();
                    permissionList = systemUserVO.getPermissionList();
                    isSuper = systemUserVO.getIsSuper();
                    isAdmin = systemUserVO.getIsAdmin();
                    permissionType = systemUserVO.getPermissionType();
                    roleDataScopeDeptIdList = systemUserVO.getRoleDataScopeDeptIdList();
                    roleDataScopeUserIdList = systemUserVO.getRoleDataScopeUserIdList();
                    break;
                default:
            }
        } else if (ObjectUtil.equal(loginAccountType, LoginAccountType.MOBILE)) {
            //先验证短信验证码
            this.validateService.checkSmsCaptcha(username, password);

            //再验证用户身份
            switch (loginEndpointType) {
                case SYSTEM:
                    Result result1 = iAdminFeignClient.loginCheckByPhone(username);
                    if (result1.hasError()) {
                        return result1;
                    }
                    SystemUserVO systemUserVO = result1.getData(SystemUserVO.class);
                    userid = systemUserVO.getUserid();
                    username = systemUserVO.getUsername();
                    name = systemUserVO.getName();
                    deptId = systemUserVO.getDeptId();
                    roleList = systemUserVO.getRoleList();
                    permissionList = systemUserVO.getPermissionList();
                    isSuper = systemUserVO.getIsSuper();
                    isAdmin = systemUserVO.getIsAdmin();
                    permissionType = systemUserVO.getPermissionType();
                    roleDataScopeDeptIdList = systemUserVO.getRoleDataScopeDeptIdList();
                    roleDataScopeUserIdList = systemUserVO.getRoleDataScopeUserIdList();
                    break;
                default:
            }
        } else {
            return Result.error("登录方式错误");
        }

        StpUtil.login(userid, loginEndpointType.getValue());
        SaSession session = StpUtil.getSession();
        SaSession tokenSession = StpUtil.getTokenSession();
        User user = new User(userid, username, name, deptId, loginEndpointType.getValue(), null, isSuper, isAdmin, permissionType, roleDataScopeDeptIdList, roleDataScopeUserIdList);
        session.set(SaTokenConstant.SESSION_USER_KEY, user);
        tokenSession.set(SaTokenConstant.SESSION_USER_KEY, user);
        this.redisSecurityUtil.loginAfterProcess(StpUtil.getTokenValue(), user, roleList, permissionList);

        //记录登录日志
        com.linsen.core.log.model.Log logModel = new com.linsen.core.log.model.Log()
                .setLogType(LogType.LOGIN)
                .setLoginType(LoginType.LOGININ)
                .setEndpointType(loginEndpointType)
                .setTraceId(request.getHeader(LinsenConstant.LINSEN_TRACE_ID))
                .setIp(IpUtils.getIpAddressUseNginx(request))
                .setUserAgent(request.getHeader(HttpHeaders.USER_AGENT))
                .setCreateBy(userid)
                .setCreateByName(username)
                .setCreateTime(LocalDateTime.now());
        this.applicationContext.publishEvent(new LogEvent(logModel));

        return Result.ok("登录成功", ConvertUtil.convert(StpUtil.getTokenInfo(), LoginVO.class));
    }

    @ApiOperation(value = "PC退出登录")
    @PostMapping("/logout")
    public Result logout(@RequestHeader(AuthConstant.TOKEN_NAME) String tokenValue, HttpServletRequest request) {
        if (StrUtil.isBlank(tokenValue)) {
            throw new RequestBusinessException("退出登录失败");
        }

        String userid = StpUtil.getLoginIdAsString();
        User user = this.redisSecurityUtil.getUser(TokenContextHolder.getToken());
        String username = user.getUsername();
        String loginEndpointType = user.getLoginEndpointType();

        this.redisSecurityUtil.logoutBeforeProcess(tokenValue);
        StpUtil.logoutByTokenValue(tokenValue);

        //记录退出登录日志
        com.linsen.core.log.model.Log logModel = new com.linsen.core.log.model.Log()
                .setLogType(LogType.LOGIN)
                .setLoginType(LoginType.LOGINOUT)
                .setEndpointType(LoginEndpointType.getByValue(loginEndpointType))
                .setTraceId(request.getHeader(LinsenConstant.LINSEN_TRACE_ID))
                .setIp(IpUtils.getIpAddressUseNginx(request))
                .setUserAgent(request.getHeader(HttpHeaders.USER_AGENT))
                .setCreateBy(userid)
                .setCreateByName(username)
                .setCreateTime(LocalDateTime.now());
        this.applicationContext.publishEvent(new LogEvent(logModel));

        return Result.ok("退出登录成功");
    }

//    @ApiOperation(value = "APP退出登录")
//    @PostMapping("/app/logout")
//    public Result appLogout(@RequestHeader(AuthConstant.TOKEN_NAME) String tokenValue, HttpServletRequest request) {
//        if (StrUtil.isBlank(tokenValue)) {
//            throw new RequestBusinessException("退出登录失败");
//        }
//
//        this.redisSecurityUtil.logoutBeforeProcess(tokenValue);
//        StpUtil.logoutByTokenValue(tokenValue);
//
//        return Result.ok("退出登录成功");
//    }
}
